import { existsSync, readFileSync, writeFileSync } from "fs";

type ConcertConfig = {
  date: number[];
  session: number[];
  price: number[];
  real_name: number;
  nick_name: string;
  ticket_num: number;
  viewer_person: number[];
  damai_url: string;
  target_url: string;
  driver_path: string;
};

class Concert {
  private browser: WebdriverIO.Browser;

  private date: number[];
  private session: number[];
  private price: number[];
  private real_name: number;
  private status: number;
  private time_end: number;
  private num: number;
  private ticket_num: number;
  private viewer_person: number[];
  private damai_url: string;
  private target_url: string;

  constructor(browser: WebdriverIO.Browser, config: ConcertConfig) {
    this.browser = browser;
    this.date = config.date;
    this.session = config.session;
    this.price = config.price;
    this.real_name = config.real_name;
    this.ticket_num = config.ticket_num;
    this.viewer_person = config.viewer_person;
    this.damai_url = config.damai_url;
    this.target_url = config.target_url;
    this.status = 0;
    this.time_end = 0;
    this.num = 0;
  }

  async getCookie(): Promise<void> {
    console.log("###获取Cookie###");
    await this.browser.url(this.damai_url);
    console.log("###请点击登录###");

    const loginUser = this.browser.$(".login-user");
    await loginUser.click();

    while (
      (await this.browser.getTitle()).indexOf(
        "大麦网-全球演出赛事官方购票平台"
      ) === -1
    ) {
      await this.browser.pause(1000);
    }

    console.log("###请扫码登录###");
    while ((await this.browser.getTitle()) === "大麦登录") {
      await this.browser.pause(1000);
    }

    const cookies = await this.browser.getCookies();
    writeFileSync("cookies.pkl", JSON.stringify(cookies));
    console.log("###Cookie保存成功###");
  }

  async setCookie(): Promise<void> {
    try {
      const cookies = JSON.parse(readFileSync("cookies.pkl", "utf8"));
      for (const cookie of cookies) {
        await this.browser.setCookies({
          name: cookie.name,
          value: cookie.value,
          path: "/",
          domain: ".damai.cn",
          secure: false,
          httpOnly: false,
        });
      }
      console.log("###载入Cookie###");
    } catch (e) {
      console.error(e);
    }
  }

  async login(): Promise<void> {
    console.log("###开始登录###");
    await this.browser.url(this.damai_url);
    await this.setCookie();
  }

  async enterConcert(): Promise<void> {
    if (!existsSync("cookies.pkl")) {
      console.log("###Cookie文件不存在，开始获取Cookie###");
      await this.browser.url(this.damai_url);
      console.log("###浏览器已打开###");
      await this.getCookie();
    }

    await this.login();
    await this.browser.url(this.target_url);
  }
  // 封装日期选择逻辑
  private async selectDate(): Promise<void> {
    try {
      const datePicker = this.browser.$(".bui-dm-sku-calendar");
      console.log("###开始选择日期###");
      const isExistingDate = await datePicker.isExisting();
      if (isExistingDate) {
        const dates = datePicker.$$(".day-item");
        console.log(`✅ 检测到日期选择组件，包含 ${dates.length} 个日期`);
        // 循环检测到的日期并在可选日期中选择
        if (this.date.length === 0) {
          console.warn("⚠️ 未指定日期，可能不需要选择");
          return;
        }
        const maxDateIndex = (await dates.length) - 1;
        if (this.date.some((d) => d < 1 || d > maxDateIndex)) {
          throw new Error("❌ 日期索引超出范围，请检查配置");
        }
        // 选择指定日期（可选日期范围是个数组）
        for (let index = 0; index < maxDateIndex; index++) {
          const element = dates[index];
          if (this.date.includes(index) && (await element.isDisplayed())) {
            await element.click();
            console.log(`✅ 已选择第 ${index + 1} 个日期`);
            return;
          }
        }
        return;
      } else {
        console.warn("⚠️ 未找到日期选择组件，可能不需要选择");
      }
    } catch (e) {
      console.warn("⚠️ 未找到日期选择组件，可能不需要选择");
    }
  }

  // 封装场次选择逻辑（带状态判断）
  private async selectSession(): Promise<void> {
    try {
      const sessionCard = this.browser.$(".sku-times-card");
      if (await sessionCard.isExisting()) {
        const sessions = sessionCard.$$(".bui-dm-sku-card-item");

        for (const index of this.session) {
          if (index > (await sessions.length)) continue;
          const sessionItem = sessions[index - 1];
          const tag = sessionItem.$(".item-tag");

          if (await tag.isExisting()) {
            const tagText = await tag.getText();
            if (tagText.includes("无票")) continue;
          }

          await sessionItem.click();
          console.log(`✅ 已选择第 ${index} 个场次`);
          return;
        }
        throw new Error("❌ 没有可选的场次");
      }
    } catch (e) {
      console.warn("⚠️ 未找到场次选择组件，可能不需要选择");
    }
  }

  // 封装票价选择逻辑（跳过缺货）
  private async selectPrice(): Promise<void> {
    try {
      const priceCard = this.browser.$(".sku-tickets-card");
      if (await priceCard.isExisting()) {
        const prices = priceCard.$$(".bui-dm-sku-card-item");

        for (const index of this.price) {
          console.log(`正在选择第 ${index} 价格`);

          if (index > (await prices.length)) continue;
          const priceItem = prices[index - 1];
          const tag = priceItem.$(".item-tag");

          if (
            (await tag.isExisting()) &&
            (await tag.getText()).includes("缺货")
          ) {
            continue;
          }

          await priceItem.click();
          console.log(`✅ 已选择第 ${index} 个票价`);
          return;
        }
        throw new Error("❌ 没有可选的票价");
      }
    } catch (e) {
      console.warn("⚠️ 未找到票价选择组件，可能不需要选择");
    }
  }

  async chooseTicket(): Promise<void> {
    while (!(await this.browser.getTitle()).includes("订单确认")) {
      console.log("###进入抢票界面###");
      if (this.num > 100) {
        throw new Error(
          "🔁 已尝试超过100次，可能是网络问题或页面加载异常，请检查网络连接或手动刷新页面"
        );
      }
      this.num += 1;

      if ((await this.browser.getUrl()).includes("buy.damai.cn")) break;

      const box = this.browser.$("#root");
      if (!(await box.isExisting())) {
        console.log("❌ 页面刷新失败，请检查是否被拦截");
        continue;
      }
      console.log("✅ 页面刷新成功，检测到 #root 元素");
      // 处理实名弹窗
      const realnamePopup = box.$$(".realname-popup");
      if ((await realnamePopup.length) > 0) {
        const knownButton = realnamePopup[0].$(".operate .button");
        await knownButton.click();
      }

      const buyButton = box.$(".buy-button");
      const buyButtonText = await buyButton.getText();
      console.log(`✅ 检测到购买按钮，文本为: ${buyButtonText}`);

      if (buyButtonText.includes("即将开抢")) {
        this.status = 2;
        throw new Error("---尚未开售，刷新等待---");
      }

      if (buyButtonText.includes("缺货")) {
        throw new Error("---已经缺货了---");
      }

      await buyButton.click();
      console.log("✅ 点击购买按钮");
      // 判断页面地址是否跳转到登录页面
      if ((await this.browser.getUrl()) !== this.target_url) {
        await this.getCookie();
      }

      // 如果cookies过期了 则重新登录
      // if (await this.browser.$("#alibaba-login-box").isExisting()) {
      //   console.log("### Cookie已过期，重新登录 ###");
      //   await this.login();
      // }
      //   等待页面出现 sku-pop-wrapper
      await this.browser.waitUntil(
        async () => await this.browser.$(".sku-pop-wrapper").isExisting(),
        {
          timeout: 5000,
          timeoutMsg: "长时间未出现 sku-pop-wrapper",
        }
      );
      await this.browser.pause(100);
      // 选择日期、场次、票价
      await this.selectDate();
      await this.browser.pause(100);
      await this.selectSession();
      await this.browser.pause(100);
      await this.selectPrice();

      const skuBox = this.browser.$(".sku-pop-wrapper");
      const ticketNumUp = skuBox.$(".plus-enable");

      if (!(await ticketNumUp.isExisting())) {
        if (buyButtonText === "选座购买") {
          await buyButton.click();
          this.status = 5;
          console.log("⚠️ 请自行选择位置和票价");
          break;
        } else if (buyButtonText === "提交缺货登记") {
          throw new Error("🛒 票已售罄，请前往官网提交缺货登记");
        } else {
          throw new Error("***Error: ticket_num_up 位置找不到***");
        }
      }
      const skuFooterBuyButton = skuBox.$(".sku-footer-buy-button");
      const skuFooterBuyButtonText = await skuFooterBuyButton.getText();
      if (
        ["立即预订", "立即购买", "确定", "立即购票"].includes(
          skuFooterBuyButtonText
        )
      ) {
        for (let i = 1; i < this.ticket_num; i++) {
          await ticketNumUp.click();
        }
        await skuFooterBuyButton.click();
        this.status = 4;

        await this.browser.waitUntil(
          async () => (await this.browser.getTitle()).includes("确认购买"),
          {
            timeout: 3000,
            timeoutMsg: "长时间未跳转到确认页",
          }
        );
        console.log("###已跳转到订单确认页###");
        break;
      } else {
        throw new Error(`未定义按钮：${skuFooterBuyButtonText}`);
      }
    }
  }

  async checkOrder(): Promise<void> {
    console.log("###开始检查订单###");
    // 等待root元素加载
    const root = this.browser.$("#app");
    await this.browser.waitUntil(async () => await root.isExisting(), {
      timeout: 5000,
      timeoutMsg: "长时间未出现 #app 元素",
    });
    if ([3, 4, 5].includes(this.status)) {
      const dmViewerBlock_DmViewerBlock = this.browser.$(
        "#dmViewerBlock_DmViewerBlock"
      );
      await this.browser.pause(1000);
      const people = dmViewerBlock_DmViewerBlock.$$(".icondanxuan-weixuan_");
      console.log(`###检测到观众人数: ${await people.length}人###`);
      if ((await people.length) > 0) {
        for (const i of this.viewer_person) {
          if (i <= (await people.length)) {
            console.log(`###选择第 ${i}个观众###`);

            await people[i - 1].click();
            await this.browser.pause(50);
          }
        }
        const element = this.browser.$('[data-tpl-id*="Submit"]');
        const confirmBtn = element.$(
          "[view-name=FrameLayout] > [view-name=TextView] > span"
        );

        if (!(await confirmBtn.isExisting())) {
          throw new Error("###确认按钮不存在，请检查页面###");
        }
        await confirmBtn.click();

        console.log(
          "###等待跳转到--付款界面--，可自行刷新，若长期不跳转可选择-- CRTL+C --重新抢票###"
        );

        try {
          await this.browser.waitUntil(
            async () => (await this.browser.getTitle()).includes("支付宝"),
            {
              timeout: 4000,
              timeoutMsg: "长时间未跳转到支付页",
            }
          );
        } catch {
          console.log("⚠️ 未能自动识别跳转，进入人工干预模式...");
          console.log("请输入指令:");
          console.log("1: 抢票成功（跳转完成）");
          console.log("2: 抢票失败，继续下一轮尝试");

          const readline = require("readline").createInterface({
            input: process.stdin,
            output: process.stdout,
          });

          const answer = await new Promise<string>((resolve) => {
            readline.question("请选择:", resolve);
          });
          readline.close();

          if (answer === "1") {
            this.status = 6;
            console.log("✅ 用户确认订单提交成功");
          } else {
            throw new Error("🔁 用户取消，准备重试...");
          }
        }

        this.status = 6;
        console.log("###成功提交订单,请手动支付###");
        this.time_end = Date.now();
      }
    }
  }
}

export default Concert;
